/*
 *  Gurr - A multiprotocol chat client for Android
 *  Copyright (C) 2011 Malte Aschermann, Wilfried Ramaker
 *  
 *  This file is part of Gurr.
 *  
 *  Gurr is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  Gurr is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Gurr.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.masc.gurr.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.kano.joscar.ssiitem.GroupItem;

public class Group {
	
	private int fCurrentFreeUid=1;
	private List<Integer> fUsedUids = new ArrayList<Integer>();
	private String name;
	private int gid;
	private ArrayList<Contact> fListContacts;
	private ArrayList<Group> fListSubgroups;
	private Group fParentGroupRef;
	private Map<String, Contact> fMapUinContact;
	private boolean expanded;
	private GroupItem fMyGroupItem;
	
	public Group(String name) {
		this.name = name;
		fListSubgroups = new ArrayList<Group>();
		fListContacts = new ArrayList<Contact>();
		fParentGroupRef=null;
		fMapUinContact = new HashMap<String, Contact>();
		expanded = false;
		fMyGroupItem = null;
	}
	
	public Group(int gid) {
		this.gid = gid;
		fListSubgroups = new ArrayList<Group>();
		fListContacts = new ArrayList<Contact>();
		fParentGroupRef=null;
		fMapUinContact = new HashMap<String, Contact>();
		expanded = false;
		fMyGroupItem = null;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public Iterator<Contact> getContacts() {
		return fListContacts.iterator();
	}
	
	public List<Contact> getContactsList() {
		return fListContacts;
	}
	
	public void setContacts(ArrayList<Contact> contacts) {
		this.fListContacts = contacts;
	}
	
	public Iterator<Group> getSubgroups() {
		return fListSubgroups.iterator();
	}
	
	public void removeSubGroup(Group subgroup) {
		subgroup.setParentGroup(null);
		
		/* remove all map entries from subgroups in parent (this) group's map */
		Iterator<String> it = subgroup.getMap().keySet().iterator();
		while (it.hasNext()) {
			fMapUinContact.remove(it.next());
		}
		
		this.fListSubgroups.remove(subgroup);
	}
	
	public void addSubGroup(Group pSubGroup) {
		this.fListSubgroups.add(pSubGroup);
		pSubGroup.setParentGroup(this);
		fMapUinContact.putAll(pSubGroup.getMap());
	
	}
	
	public Map<String, Contact> getMap() {
		return fMapUinContact;
	}

	public void addContact(Contact pContact) {
		this.fListContacts.add(pContact);
		if (pContact.getUin()!=null)
			addContactToMap(pContact);
		pContact.setGroupRef(this);
		
		/* give contact item a fresh new, unused uid, if not set or already taken */
		if(pContact.getUid() == -1 || fUsedUids.contains(pContact.getUid())) {
			pContact.setUid(fCurrentFreeUid);
			fUsedUids.add(fCurrentFreeUid);
		} else { /* add the contact's uid to used list */
			fUsedUids.add(pContact.getUid());
		}

		findNextFreeUid();
	}
	
	protected void removeContactFromList(Contact pContact) {
		fListContacts.remove(pContact);
	}
	
	public void removeContact(String pStrUin) {
		Contact contact = fMapUinContact.get(pStrUin);
		
		/* remove contact from all (parent) maps */
		removeContactFromMap(contact);
		
		/* remove reference from contact's parent group to contact */
	    Group parentGroup = contact.getGroupRef();
	    if (parentGroup != null) {
	    	parentGroup.removeContactFromList(contact);
	    }
	    
	    /* remove reference to parent group */
		contact.setGroupRef(null);

		/* remove used uid */
		fUsedUids.remove(contact.getUid());

		/* find a fresh new, unused uid (this uid, or a smaller one) */
		findNextFreeUid();
		
	}

	private void findNextFreeUid() {
		fCurrentFreeUid=0;
		do
			fCurrentFreeUid++;
		while (	fUsedUids.contains(fCurrentFreeUid) );
	}

	public Group getParentGroup() {
		return fParentGroupRef;
	}

	public void setParentGroup(Group parentGroupRef) {
		this.fParentGroupRef = parentGroupRef;
	}

	public int getGid() {
		return gid;
	}

	public void setGid(int gid) {
		this.gid = gid;
	}

	@Deprecated
	public void removeAll() {
		
		/** unlink groups/contacts */
		Iterator<Contact> itc = getContacts();
		while (itc.hasNext()) {
			Contact contact = (Contact) itc.next();
			contact.setGroupRef(null);
		}
		Iterator<Group> itg = getSubgroups();
		while (itg.hasNext()) {
			Group group = (Group) itg.next();
			group.getParentGroup();
		}
		
		this.fListContacts = new ArrayList<Contact>();
		this.fListSubgroups = new ArrayList<Group>();
	}
	
	public void addContactToMap(Contact c) {
		/* never add a contact w/ null uin to map */
		if (c.getUin() == null)
			return;
		
		fMapUinContact.put(c.getUin(), c);
		if (fParentGroupRef != null)
			fParentGroupRef.addContactToMap(c);
	}
	
	public void removeContactFromMap(Contact c) {
		fMapUinContact.remove(c.getUin());
		if (fParentGroupRef != null)
			fParentGroupRef.removeContactFromMap(c);
	}
	
	public Contact getChildContact(String pStrUin) {
		return fMapUinContact.get(pStrUin);
	}

	public boolean isExpanded() {
		return expanded;
	}

	public void setExpanded(boolean expanded) {
		this.expanded = expanded;
	}

	public int getfCurrentFreeUid() {
		return fCurrentFreeUid;
	}

	public void setfCurrentFreeUid(int fCurrentFreeUid) {
		this.fCurrentFreeUid = fCurrentFreeUid;
	}

	public GroupItem getfMyGroupItem() {
		return fMyGroupItem;
	}

	public void setfMyGroupItem(GroupItem fMyGroupItem) {
		this.fMyGroupItem = fMyGroupItem;
	}
	
	public GroupItem toGroupItem(){
		fMyGroupItem = new GroupItem(name, gid);
		return fMyGroupItem;
	}
	
}

